home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xllist.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  20.4 KB  |  955 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xllist.c
  5. * RCS:          $Header: xllist.c,v 1.4 91/03/24 22:25:09 mayer Exp $
  6. * Description:  xlisp built-in list functions
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 04:05:52 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xllist.c,v 1.4 91/03/24 22:25:09 mayer Exp $";
  42.  
  43.  
  44. #include "xlisp.h"
  45.  
  46. /* forward declarations */
  47. LOCAL FORWARD LVAL cxr();    /* NPM: changed this to LOCAL */
  48. LOCAL FORWARD LVAL nth(),assoc(); /* NPM: changed this to LOCAL */
  49. LOCAL FORWARD LVAL subst(),sublis(),map(); /* NPM: changed this to LOCAL */
  50.  
  51. /* xcar - take the car of a cons cell */
  52. LVAL xcar()
  53. {
  54.     LVAL list;
  55.     list = xlgalist();
  56.     xllastarg();
  57.     return (list ? car(list) : NIL);
  58. }
  59.  
  60. /* xcdr - take the cdr of a cons cell */
  61. LVAL xcdr()
  62. {
  63.     LVAL list;
  64.     list = xlgalist();
  65.     xllastarg();
  66.     return (list ? cdr(list) : NIL);
  67. }
  68.  
  69. /* cxxr functions */
  70. LVAL xcaar() { return (cxr("aa")); }
  71. LVAL xcadr() { return (cxr("da")); }
  72. LVAL xcdar() { return (cxr("ad")); }
  73. LVAL xcddr() { return (cxr("dd")); }
  74.  
  75. /* cxxxr functions */
  76. LVAL xcaaar() { return (cxr("aaa")); }
  77. LVAL xcaadr() { return (cxr("daa")); }
  78. LVAL xcadar() { return (cxr("ada")); }
  79. LVAL xcaddr() { return (cxr("dda")); }
  80. LVAL xcdaar() { return (cxr("aad")); }
  81. LVAL xcdadr() { return (cxr("dad")); }
  82. LVAL xcddar() { return (cxr("add")); }
  83. LVAL xcdddr() { return (cxr("ddd")); }
  84.  
  85. /* cxxxxr functions */
  86. LVAL xcaaaar() { return (cxr("aaaa")); }
  87. LVAL xcaaadr() { return (cxr("daaa")); }
  88. LVAL xcaadar() { return (cxr("adaa")); }
  89. LVAL xcaaddr() { return (cxr("ddaa")); }
  90. LVAL xcadaar() { return (cxr("aada")); }
  91. LVAL xcadadr() { return (cxr("dada")); }
  92. LVAL xcaddar() { return (cxr("adda")); }
  93. LVAL xcadddr() { return (cxr("ddda")); }
  94. LVAL xcdaaar() { return (cxr("aaad")); }
  95. LVAL xcdaadr() { return (cxr("daad")); }
  96. LVAL xcdadar() { return (cxr("adad")); }
  97. LVAL xcdaddr() { return (cxr("ddad")); }
  98. LVAL xcddaar() { return (cxr("aadd")); }
  99. LVAL xcddadr() { return (cxr("dadd")); }
  100. LVAL xcdddar() { return (cxr("addd")); }
  101. LVAL xcddddr() { return (cxr("dddd")); }
  102.  
  103. /* cxr - common car/cdr routine */
  104. LOCAL LVAL cxr(adstr)
  105.   char *adstr;
  106. {
  107.     LVAL list;
  108.  
  109.     /* get the list */
  110.     list = xlgalist();
  111.     xllastarg();
  112.  
  113.     /* perform the car/cdr operations */
  114.     while (*adstr && consp(list))
  115.     list = (*adstr++ == 'a' ? car(list) : cdr(list));
  116.  
  117.     /* make sure the operation succeeded */
  118.     if (*adstr && list)
  119.     xlfail("bad argument");
  120.  
  121.     /* return the result */
  122.     return (list);
  123. }
  124.  
  125. /* xcons - construct a new list cell */
  126. LVAL xcons()
  127. {
  128.     LVAL arg1,arg2;
  129.  
  130.     /* get the two arguments */
  131.     arg1 = xlgetarg();
  132.     arg2 = xlgetarg();
  133.     xllastarg();
  134.  
  135.     /* construct a new list element */
  136.     return (cons(arg1,arg2));
  137. }
  138.  
  139. /* xlist - built a list of the arguments */
  140. LVAL xlist()
  141. {
  142.     LVAL last,next,val;
  143.  
  144.     /* protect some pointers */
  145.     xlsave1(val);
  146.  
  147.     /* add each argument to the list */
  148.     for (val = NIL; moreargs(); ) {
  149.  
  150.     /* append this argument to the end of the list */
  151.     next = consa(nextarg());
  152.     if (val) rplacd(last,next);
  153.     else val = next;
  154.     last = next;
  155.     }
  156.  
  157.     /* restore the stack */
  158.     xlpop();
  159.  
  160.     /* return the list */
  161.     return (val);
  162. }
  163.  
  164. /* xappend - built-in function append */
  165. LVAL xappend()
  166. {
  167.     LVAL list,last,next,val;
  168.  
  169.     /* protect some pointers */
  170.     xlsave1(val);
  171.  
  172.     /* initialize */
  173.     val = NIL;
  174.     
  175.     /* append each argument */
  176.     if (moreargs()) {
  177.     while (xlargc > 1) {
  178.  
  179.         /* append each element of this list to the result list */
  180.         for (list = nextarg(); consp(list); list = cdr(list)) {
  181.         next = consa(car(list));
  182.         if (val) rplacd(last,next);
  183.         else val = next;
  184.         last = next;
  185.         }
  186.     }
  187.  
  188.     /* handle the last argument */
  189.     if (val) rplacd(last,nextarg());
  190.     else val = nextarg();
  191.     }
  192.  
  193.     /* restore the stack */
  194.     xlpop();
  195.  
  196.     /* return the list */
  197.     return (val);
  198. }
  199.  
  200. /* xreverse - built-in function reverse */
  201. LVAL xreverse()
  202. {
  203.     LVAL list,val;
  204.  
  205.     /* protect some pointers */
  206.     xlsave1(val);
  207.  
  208.     /* get the list to reverse */
  209.     list = xlgalist();
  210.     xllastarg();
  211.  
  212.     /* append each element to the head of the result list */
  213.     for (val = NIL; consp(list); list = cdr(list))
  214.     val = cons(car(list),val);
  215.  
  216.     /* restore the stack */
  217.     xlpop();
  218.  
  219.     /* return the list */
  220.     return (val);
  221. }
  222.  
  223. /* xlast - return the last cons of a list */
  224. LVAL xlast()
  225. {
  226.     LVAL list;
  227.  
  228.     /* get the list */
  229.     list = xlgalist();
  230.     xllastarg();
  231.  
  232.     /* find the last cons */
  233.     while (consp(list) && cdr(list))
  234.     list = cdr(list);
  235.  
  236.     /* return the last element */
  237.     return (list);
  238. }
  239.  
  240. /* xmember - built-in function 'member' */
  241. LVAL xmember()
  242. {
  243.     LVAL x,list,fcn,val;
  244.     int tresult;
  245.  
  246.     /* protect some pointers */
  247.     xlsave1(fcn);
  248.  
  249.     /* get the expression to look for and the list */
  250.     x = xlgetarg();
  251.     list = xlgalist();
  252.     xltest(&fcn,&tresult);
  253.  
  254.     /* look for the expression */
  255.     for (val = NIL; consp(list); list = cdr(list))
  256.     if (dotest2(x,car(list),fcn) == tresult) {
  257.         val = list;
  258.         break;
  259.     }
  260.  
  261.     /* restore the stack */
  262.     xlpop();
  263.  
  264.     /* return the result */
  265.     return (val);
  266. }
  267.  
  268. /* xassoc - built-in function 'assoc' */
  269. LVAL xassoc()
  270. {
  271.     LVAL x,alist,fcn,pair,val;
  272.     int tresult;
  273.  
  274.     /* protect some pointers */
  275.     xlsave1(fcn);
  276.  
  277.     /* get the expression to look for and the association list */
  278.     x = xlgetarg();
  279.     alist = xlgalist();
  280.     xltest(&fcn,&tresult);
  281.  
  282.     /* look for the expression */
  283.     for (val = NIL; consp(alist); alist = cdr(alist))
  284.     if ((pair = car(alist)) && consp(pair))
  285.         if (dotest2(x,car(pair),fcn) == tresult) {
  286.         val = pair;
  287.         break;
  288.         }
  289.  
  290.     /* restore the stack */
  291.     xlpop();
  292.  
  293.     /* return result */
  294.     return (val);
  295. }
  296.  
  297. /* xsubst - substitute one expression for another */
  298. LVAL xsubst()
  299. {
  300.     LVAL to,from,expr,fcn,val;
  301.     int tresult;
  302.  
  303.     /* protect some pointers */
  304.     xlsave1(fcn);
  305.  
  306.     /* get the to value, the from value and the expression */
  307.     to = xlgetarg();
  308.     from = xlgetarg();
  309.     expr = xlgetarg();
  310.     xltest(&fcn,&tresult);
  311.  
  312.     /* do the substitution */
  313.     val = subst(to,from,expr,fcn,tresult);
  314.  
  315.     /* restore the stack */
  316.     xlpop();
  317.  
  318.     /* return the result */
  319.     return (val);
  320. }
  321.  
  322. /* subst - substitute one expression for another */
  323. LOCAL LVAL subst(to,from,expr,fcn,tresult)
  324.   LVAL to,from,expr,fcn; int tresult;
  325. {
  326.     LVAL carval,cdrval;
  327.  
  328.     if (dotest2(expr,from,fcn) == tresult)
  329.     return (to);
  330.     else if (consp(expr)) {
  331.     xlsave1(carval);
  332.     carval = subst(to,from,car(expr),fcn,tresult);
  333.     cdrval = subst(to,from,cdr(expr),fcn,tresult);
  334.     xlpop();
  335.     return (cons(carval,cdrval));
  336.     }
  337.     else
  338.     return (expr);
  339. }
  340.  
  341. /* xsublis - substitute using an association list */
  342. LVAL xsublis()
  343. {
  344.     LVAL alist,expr,fcn,val;
  345.     int tresult;
  346.  
  347.     /* protect some pointers */
  348.     xlsave1(fcn);
  349.  
  350.     /* get the assocation list and the expression */
  351.     alist = xlgalist();
  352.     expr = xlgetarg();
  353.     xltest(&fcn,&tresult);
  354.  
  355.     /* do the substitution */
  356.     val = sublis(alist,expr,fcn,tresult);
  357.  
  358.     /* restore the stack */
  359.     xlpop();
  360.  
  361.     /* return the result */
  362.     return (val);
  363. }
  364.  
  365. /* sublis - substitute using an association list */
  366. LOCAL LVAL sublis(alist,expr,fcn,tresult)
  367.   LVAL alist,expr,fcn; int tresult;
  368. {
  369.     LVAL carval,cdrval,pair;
  370.  
  371.     if (pair = assoc(expr,alist,fcn,tresult))
  372.     return (cdr(pair));
  373.     else if (consp(expr)) {
  374.     xlsave1(carval);
  375.     carval = sublis(alist,car(expr),fcn,tresult);
  376.     cdrval = sublis(alist,cdr(expr),fcn,tresult);
  377.     xlpop();
  378.     return (cons(carval,cdrval));
  379.     }
  380.     else
  381.     return (expr);
  382. }
  383.  
  384. /* assoc - find a pair in an association list */
  385. LOCAL LVAL assoc(expr,alist,fcn,tresult)
  386.   LVAL expr,alist,fcn; int tresult;
  387. {
  388.     LVAL pair;
  389.  
  390.     for (; consp(alist); alist = cdr(alist))
  391.     if ((pair = car(alist)) && consp(pair))
  392.         if (dotest2(expr,car(pair),fcn) == tresult)
  393.         return (pair);
  394.     return (NIL);
  395. }
  396.  
  397. /* xremove - built-in function 'remove' */
  398. LVAL xremove()
  399. {
  400.     LVAL x,list,fcn,val,last,next;
  401.     int tresult;
  402.  
  403.     /* protect some pointers */
  404.     xlstkcheck(2);
  405.     xlsave(fcn);
  406.     xlsave(val);
  407.  
  408.     /* get the expression to remove and the list */
  409.     x = xlgetarg();
  410.     list = xlgalist();
  411.     xltest(&fcn,&tresult);
  412.  
  413.     /* remove matches */
  414.     for (; consp(list); list = cdr(list))
  415.  
  416.     /* check to see if this element should be deleted */
  417.     if (dotest2(x,car(list),fcn) != tresult) {
  418.         next = consa(car(list));
  419.         if (val) rplacd(last,next);
  420.         else val = next;
  421.         last = next;
  422.     }
  423.  
  424.     /* restore the stack */
  425.     xlpopn(2);
  426.  
  427.     /* return the updated list */
  428.     return (val);
  429. }
  430.  
  431. /* xremif - built-in function 'remove-if' */
  432. LVAL xremif()
  433. {
  434.     LVAL remif();
  435.     return (remif(TRUE));
  436. }
  437.  
  438. /* xremifnot - built-in function 'remove-if-not' */
  439. LVAL xremifnot()
  440. {
  441.     LVAL remif();
  442.     return (remif(FALSE));
  443. }
  444.  
  445. /* remif - common code for 'remove-if' and 'remove-if-not' */
  446. LOCAL LVAL remif(tresult)
  447.   int tresult;
  448. {
  449.     LVAL list,fcn,val,last,next;
  450.  
  451.     /* protect some pointers */
  452.     xlstkcheck(2);
  453.     xlsave(fcn);
  454.     xlsave(val);
  455.  
  456.     /* get the expression to remove and the list */
  457.     fcn = xlgetarg();
  458.     list = xlgalist();
  459.     xllastarg();
  460.  
  461.     /* remove matches */
  462.     for (; consp(list); list = cdr(list))
  463.  
  464.     /* check to see if this element should be deleted */
  465.     if (dotest1(car(list),fcn) != tresult) {
  466.         next = consa(car(list));
  467.         if (val) rplacd(last,next);
  468.         else val = next;
  469.         last = next;
  470.     }
  471.  
  472.     /* restore the stack */
  473.     xlpopn(2);
  474.  
  475.     /* return the updated list */
  476.     return (val);
  477. }
  478.  
  479. /* dotest1 - call a test function with one argument */
  480. int dotest1(arg,fun)
  481.   LVAL arg,fun;
  482. {
  483.     LVAL *newfp;
  484.  
  485.     /* create the new call frame */
  486.     newfp = xlsp;
  487.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  488.     pusharg(fun);
  489.     pusharg(cvfixnum((FIXTYPE)1));
  490.     pusharg(arg);
  491.     xlfp = newfp;
  492.  
  493.     /* return the result of applying the test function */
  494.     return (xlapply(1) != NIL);
  495.  
  496. }
  497.  
  498. /* dotest2 - call a test function with two arguments */
  499. int dotest2(arg1,arg2,fun)
  500.   LVAL arg1,arg2,fun;
  501. {
  502.     LVAL *newfp;
  503.  
  504.     /* create the new call frame */
  505.     newfp = xlsp;
  506.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  507.     pusharg(fun);
  508.     pusharg(cvfixnum((FIXTYPE)2));
  509.     pusharg(arg1);
  510.     pusharg(arg2);
  511.     xlfp = newfp;
  512.  
  513.     /* return the result of applying the test function */
  514.     return (xlapply(2) != NIL);
  515.  
  516. }
  517.  
  518. /* xnth - return the nth element of a list */
  519. LVAL xnth()
  520. {
  521.     return (nth(TRUE));
  522. }
  523.  
  524. /* xnthcdr - return the nth cdr of a list */
  525. LVAL xnthcdr()
  526. {
  527.     return (nth(FALSE));
  528. }
  529.  
  530. /* nth - internal nth function */
  531. LOCAL LVAL nth(carflag)
  532.   int carflag;
  533. {
  534.     LVAL list,num;
  535.     FIXTYPE n;
  536.  
  537.     /* get n and the list */
  538.     num = xlgafixnum();
  539.     list = xlgacons();
  540.     xllastarg();
  541.  
  542.     /* make sure the number isn't negative */
  543.     if ((n = getfixnum(num)) < 0)
  544.     xlfail("bad argument");
  545.  
  546.     /* find the nth element */
  547.     while (consp(list) && --n >= 0)
  548.     list = cdr(list);
  549.  
  550.     /* return the list beginning at the nth element */
  551.     return (carflag && consp(list) ? car(list) : list);
  552. }
  553.  
  554. /* xlength - return the length of a list or string */
  555. LVAL xlength()
  556. {
  557.     FIXTYPE n;
  558.     LVAL arg;
  559.  
  560.     /* get the list or string */
  561.     arg = xlgetarg();
  562.     xllastarg();
  563.  
  564.     /* find the length of a list */
  565.     if (listp(arg))
  566.     for (n = 0; consp(arg); n++)
  567.         arg = cdr(arg);
  568.  
  569.     /* find the length of a string */
  570.     else if (stringp(arg))
  571.     n = (FIXTYPE)getslength(arg)-1;
  572.  
  573.     /* find the length of a vector */
  574.     else if (vectorp(arg))
  575.     n = (FIXTYPE)getsize(arg);
  576.  
  577.     /* otherwise, bad argument type */
  578.     else
  579.     xlerror("bad argument type",arg);
  580.  
  581.     /* return the length */
  582.     return (cvfixnum(n));
  583. }
  584.  
  585. /* xmapc - built-in function 'mapc' */
  586. LVAL xmapc()
  587. {
  588.     return (map(TRUE,FALSE));
  589. }
  590.  
  591. /* xmapcar - built-in function 'mapcar' */
  592. LVAL xmapcar()
  593. {
  594.     return (map(TRUE,TRUE));
  595. }
  596.  
  597. /* xmapl - built-in function 'mapl' */
  598. LVAL xmapl()
  599. {
  600.     return (map(FALSE,FALSE));
  601. }
  602.  
  603. /* xmaplist - built-in function 'maplist' */
  604. LVAL xmaplist()
  605. {
  606.     return (map(FALSE,TRUE));
  607. }
  608.  
  609. /* map - internal mapping function */
  610. LOCAL LVAL map(carflag,valflag)
  611.   int carflag,valflag;
  612. {
  613.     LVAL *newfp,fun,lists,val,last,p,x,y;
  614.     int argc;
  615.  
  616.     /* protect some pointers */
  617.     xlstkcheck(3);
  618.     xlsave(fun);
  619.     xlsave(lists);
  620.     xlsave(val);
  621.  
  622.     /* get the function to apply and the first list */
  623.     fun = xlgetarg();
  624.     lists = xlgalist();
  625.  
  626.     /* initialize the result list */
  627.     val = (valflag ? NIL : lists);
  628.  
  629.     /* build a list of argument lists */
  630.     for (lists = last = consa(lists); moreargs(); last = cdr(last))
  631.     rplacd(last,cons(xlgalist(),NIL));
  632.  
  633.     /* loop through each of the argument lists */
  634.     for (;;) {
  635.  
  636.     /* build an argument list from the sublists */
  637.     newfp = xlsp;
  638.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  639.     pusharg(fun);
  640.     pusharg(NIL);
  641.     argc = 0;
  642.     for (x = lists; x && (y = car(x)) && consp(y); x = cdr(x)) {
  643.         pusharg(carflag ? car(y) : y);
  644.         rplaca(x,cdr(y));
  645.         ++argc;
  646.     }
  647.  
  648.     /* quit if any of the lists were empty */
  649.     if (x) {
  650.         xlsp = newfp;
  651.         break;
  652.     }
  653.  
  654.     /* apply the function to the arguments */
  655.     newfp[2] = cvfixnum((FIXTYPE)argc);
  656.     xlfp = newfp;
  657.     if (valflag) {
  658.         p = consa(xlapply(argc));
  659.         if (val) rplacd(last,p);
  660.         else val = p;
  661.         last = p;
  662.     }
  663.     else
  664.         xlapply(argc);
  665.     }
  666.  
  667.     /* restore the stack */
  668.     xlpopn(3);
  669.  
  670.     /* return the last test expression value */
  671.     return (val);
  672. }
  673.  
  674. /* xrplca - replace the car of a list node */
  675. LVAL xrplca()
  676. {
  677.     LVAL list,newcar;
  678.  
  679.     /* get the list and the new car */
  680.     list = xlgacons();
  681.     newcar = xlgetarg();
  682.     xllastarg();
  683.  
  684.     /* replace the car */
  685.     rplaca(list,newcar);
  686.  
  687.     /* return the list node that was modified */
  688.     return (list);
  689. }
  690.  
  691. /* xrplcd - replace the cdr of a list node */
  692. LVAL xrplcd()
  693. {
  694.     LVAL list,newcdr;
  695.  
  696.     /* get the list and the new cdr */
  697.     list = xlgacons();
  698.     newcdr = xlgetarg();
  699.     xllastarg();
  700.  
  701.     /* replace the cdr */
  702.     rplacd(list,newcdr);
  703.  
  704.     /* return the list node that was modified */
  705.     return (list);
  706. }
  707.  
  708. /* xnconc - destructively append lists */
  709. LVAL xnconc()
  710. {
  711.     LVAL next,last,val;
  712.  
  713.     /* initialize */
  714.     val = NIL;
  715.     
  716.     /* concatenate each argument */
  717.     if (moreargs()) {
  718.     while (xlargc > 1) {
  719.  
  720.         /* ignore everything except lists */
  721.         if ((next = nextarg()) && consp(next)) {
  722.  
  723.         /* concatenate this list to the result list */
  724.         if (val) rplacd(last,next);
  725.         else val = next;
  726.  
  727.         /* find the end of the list */
  728.         while (consp(cdr(next)))
  729.             next = cdr(next);
  730.         last = next;
  731.         }
  732.     }
  733.  
  734.     /* handle the last argument */
  735.     if (val) rplacd(last,nextarg());
  736.     else val = nextarg();
  737.     }
  738.  
  739.     /* return the list */
  740.     return (val);
  741. }
  742.  
  743. /* xdelete - built-in function 'delete' */
  744. LVAL xdelete()
  745. {
  746.     LVAL x,list,fcn,last,val;
  747.     int tresult;
  748.  
  749.     /* protect some pointers */
  750.     xlsave1(fcn);
  751.  
  752.     /* get the expression to delete and the list */
  753.     x = xlgetarg();
  754.     list = xlgalist();
  755.     xltest(&fcn,&tresult);
  756.  
  757.     /* delete leading matches */
  758.     while (consp(list)) {
  759.     if (dotest2(x,car(list),fcn) != tresult)
  760.         break;
  761.     list = cdr(list);
  762.     }
  763.     val = last = list;
  764.  
  765.     /* delete embedded matches */
  766.     if (consp(list)) {
  767.  
  768.     /* skip the first non-matching element */
  769.     list = cdr(list);
  770.  
  771.     /* look for embedded matches */
  772.     while (consp(list)) {
  773.  
  774.         /* check to see if this element should be deleted */
  775.         if (dotest2(x,car(list),fcn) == tresult)
  776.         rplacd(last,cdr(list));
  777.         else
  778.         last = list;
  779.  
  780.         /* move to the next element */
  781.         list = cdr(list);
  782.      }
  783.     }
  784.  
  785.     /* restore the stack */
  786.     xlpop();
  787.  
  788.     /* return the updated list */
  789.     return (val);
  790. }
  791.  
  792. /* xdelif - built-in function 'delete-if' */
  793. LVAL xdelif()
  794. {
  795.     LVAL delif();
  796.     return (delif(TRUE));
  797. }
  798.  
  799. /* xdelifnot - built-in function 'delete-if-not' */
  800. LVAL xdelifnot()
  801. {
  802.     LVAL delif();
  803.     return (delif(FALSE));
  804. }
  805.  
  806. /* delif - common routine for 'delete-if' and 'delete-if-not' */
  807. LOCAL LVAL delif(tresult)
  808.   int tresult;
  809. {
  810.     LVAL list,fcn,last,val;
  811.  
  812.     /* protect some pointers */
  813.     xlsave1(fcn);
  814.  
  815.     /* get the expression to delete and the list */
  816.     fcn = xlgetarg();
  817.     list = xlgalist();
  818.     xllastarg();
  819.  
  820.     /* delete leading matches */
  821.     while (consp(list)) {
  822.     if (dotest1(car(list),fcn) != tresult)
  823.         break;
  824.     list = cdr(list);
  825.     }
  826.     val = last = list;
  827.  
  828.     /* delete embedded matches */
  829.     if (consp(list)) {
  830.  
  831.     /* skip the first non-matching element */
  832.     list = cdr(list);
  833.  
  834.     /* look for embedded matches */
  835.     while (consp(list)) {
  836.  
  837.         /* check to see if this element should be deleted */
  838.         if (dotest1(car(list),fcn) == tresult)
  839.         rplacd(last,cdr(list));
  840.         else
  841.         last = list;
  842.  
  843.         /* move to the next element */
  844.         list = cdr(list);
  845.      }
  846.     }
  847.  
  848.     /* restore the stack */
  849.     xlpop();
  850.  
  851.     /* return the updated list */
  852.     return (val);
  853. }
  854.  
  855. /* xsort - built-in function 'sort' */
  856. LVAL xsort()
  857. {
  858.     LVAL sortlist();
  859.     LVAL list,fcn;
  860.  
  861.     /* protect some pointers */
  862.     xlstkcheck(2);
  863.     xlsave(list);
  864.     xlsave(fcn);
  865.  
  866.     /* get the list to sort and the comparison function */
  867.     list = xlgalist();
  868.     fcn = xlgetarg();
  869.     xllastarg();
  870.  
  871.     /* sort the list */
  872.     list = sortlist(list,fcn);
  873.  
  874.     /* restore the stack and return the sorted list */
  875.     xlpopn(2);
  876.     return (list);
  877. }
  878.  
  879. /*
  880.     This sorting algorithm is based on a Modula-2 sort written by
  881.     Richie Bielak and published in the February 1988 issue of
  882.     "Computer Language" magazine in a letter to the editor.
  883. */
  884.  
  885. /* sortlist - sort a list using quicksort */
  886. LOCAL LVAL sortlist(list,fcn)
  887.   LVAL list,fcn;
  888. {
  889.     LVAL gluelists();
  890.     LVAL smaller,pivot,larger;
  891.     
  892.     /* protect some pointers */
  893.     xlstkcheck(3);
  894.     xlsave(smaller);
  895.     xlsave(pivot);
  896.     xlsave(larger);
  897.     
  898.     /* lists with zero or one element are already sorted */
  899.     if (consp(list) && consp(cdr(list))) {
  900.     pivot = list; list = cdr(list);
  901.     splitlist(pivot,list,&smaller,&larger,fcn);
  902.     smaller = sortlist(smaller,fcn);
  903.     larger = sortlist(larger,fcn);
  904.     list = gluelists(smaller,pivot,larger);
  905.     }
  906.  
  907.     /* cleanup the stack and return the sorted list */
  908.     xlpopn(3);
  909.     return (list);
  910. }
  911.  
  912. /* splitlist - split the list around the pivot */
  913. LOCAL splitlist(pivot,list,psmaller,plarger,fcn)
  914.   LVAL pivot,list,*psmaller,*plarger,fcn;
  915. {
  916.     LVAL next;
  917.     
  918.     /* initialize the result lists */
  919.     *psmaller = *plarger = NIL;
  920.     
  921.     /* split the list */
  922.     for (; consp(list); list = next) {
  923.     next = cdr(list);
  924.     if (dotest2(car(list),car(pivot),fcn)) {
  925.         rplacd(list,*psmaller);
  926.         *psmaller = list;
  927.     }
  928.     else {
  929.         rplacd(list,*plarger);
  930.         *plarger = list;
  931.     }
  932.     }
  933. }
  934.  
  935. /* gluelists - glue the smaller and larger lists with the pivot */
  936. LOCAL LVAL gluelists(smaller,pivot,larger)
  937.   LVAL smaller,pivot,larger;
  938. {
  939.     LVAL last;
  940.     
  941.     /* larger always goes after the pivot */
  942.     rplacd(pivot,larger);
  943.  
  944.     /* if the smaller list is empty, we're done */
  945.     if (null(smaller))
  946.     return (pivot);
  947.  
  948.     /* append the smaller to the front of the resulting list */
  949.     for (last = smaller; consp(cdr(last)); last = cdr(last))
  950.     ;
  951.     rplacd(last,pivot);
  952.     return (smaller);
  953. }
  954.